#include "gtest/gtest.h"

#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>

#include <chaos.h>

////////////////////////////////////////////////////////////////////////////////

#define T_MACHINE(x, cerf__0, cerf__1)                                         \
	TEST(ENGINES, T__##x##__SignatureDefault) {                                  \
		x machine_##x;                                                             \
                                                                               \
		std::ostringstream sign;                                                   \
		sign << std::hex << std::uppercase << std::setfill('0');                   \
		std::vector<x::size_pull> v(128, 0);                                       \
                                                                               \
		std::generate(v.begin(), v.end(),                                          \
		              [&machine_##x] { return machine_##x.pull(); });              \
                                                                               \
		for (int block : v)                                                        \
			sign << std::setw(2) << block;                                           \
                                                                               \
		EXPECT_EQ(cerf__0, sign.str());                                            \
	}                                                                            \
                                                                               \
	TEST(ENGINES, T__##x##__SignatureAdvanced) {                                 \
		x machine_##x;                                                             \
                                                                               \
		std::vector<x::size_cell> __secret_key = {0xAA, 0xBB, 0xCC};               \
		size_t __space_parameter = 33, __time_parameter = 11;                      \
		std::vector<x::size_push> __message = {0x11, 0x22, 0x33, 0x44, 0x55,       \
		                                       0x66, 0x77, 0x88, 0x99};            \
                                                                               \
		machine_##x.set_key(__secret_key);                                         \
		machine_##x.set_space(__space_parameter);                                  \
		machine_##x.set_time(__time_parameter);                                    \
                                                                               \
		for (size_t i = 0; i < __message.size(); i++)                              \
			machine_##x.push(__message[i]);                                          \
                                                                               \
		std::ostringstream sign;                                                   \
		sign << std::hex << std::uppercase << std::setfill('0');                   \
		std::vector<x::size_pull> v(128, 0);                                       \
                                                                               \
		std::generate(v.begin(), v.end(),                                          \
		              [&machine_##x] { return machine_##x.pull(); });              \
                                                                               \
		for (int block : v)                                                        \
			sign << std::setw(2) << block;                                           \
                                                                               \
		EXPECT_EQ(cerf__1, sign.str());                                            \
                                                                               \
		sign.str("");                                                              \
		sign.clear();                                                              \
                                                                               \
		machine_##x.reset();                                                       \
                                                                               \
		for (size_t i = 0; i < __message.size(); i++)                              \
			machine_##x.push(__message[i]);                                          \
                                                                               \
		std::generate(v.begin(), v.end(),                                          \
		              [&machine_##x] { return machine_##x.pull(); });              \
                                                                               \
		for (int block : v)                                                        \
			sign << std::setw(2) << block;                                           \
                                                                               \
		EXPECT_EQ(cerf__1, sign.str());                                            \
	}

/// ncg ////////////////////////////////////////////////////////////////////////

std::string ncg__cerf__0 =
    "4CCFB24A4E3CE29B6A60367EFC3610C4B93790D2A44D07B4E2B8802E63B8D633BA5FDD63BF"
    "3B13123DD25330BFCEB17A7261BCF68FB95FE54A7A7932A05F6A55F29137559754D9967126"
    "87113A82981B02855374B54292A54FF89E133249E0165CB815E851A27B2EE82F7E2B067E9E"
    "2BD46C9A73B792587280F7217D2D28153C46619FBE0575541F4471A71E7DF9AEF17DF087D4"
    "4472F318E48D4FC59CE957B65189E6DC00DE601B30B0899F1E9E2B789EDC1BA8DB4133EA61"
    "B12E51BD4ECB468FABEB3AA3CB9AD3927C5A831115E47C3F96388E8ADFC137A269A135FB47"
    "12C03991A06099B72DF1CBDA44D4B357ADB227F2279B4CC9C8B4D04E73993CD75A75BF3C10"
    "5375DFB25DF971995287EE44A800CBBDA67B81D345C784B001C4A325F81A7128568C100677"
    "68ACAD74C94C13AFFB23423F46ADDF4C9A9DA73B9AC481A8D237A924C58E053644CF4A29A0"
    "3D7B142A85C0ECD3DFFF39DE849161A0CF528A807320C4728F9303720767743921A799E778"
    "39F3D6E074F44B9CB26EC4A7D03FB6C4DC71C5FDD6E42327AEBBA3D3024CAAB0A4E28D4245"
    "4BDC36DBB739605ED2B3F48FDDDDB743D60504BE8F30228057860C37D42D8FED962D1D717A"
    "FCD5846F0E5C7A1CB8EF76D91D976B72B093A60F7FA6D46D71434D8F2A5C5D617EAB9D3B79"
    "4A99617C3998F3B2B2DEFDDE9352D19527B25860BA66CA43A4176";

std::string ncg__cerf__1 =
    "1026301DF424E9AEEBAFDED62F68E02C3EF470F8F79D6AD2787111ECC54578BB84893B2ADA"
    "2D4D4275756DA7E69F4A878FCAF0A8E211A0AA819E6C3FC4D953ED7462CE7C2B1A29061AF9"
    "E7F6323F7CE7D24719F63D2095445EB1B9C42A7E65AAA03BEADBC635DAEAEAA2C6192025AB"
    "B725F7E53C8C7308C0D20C2A17C26D62469A96000E8262A5A0E2218EDDF89341FD4448999F"
    "197E3EB18C96BB643175A46F320C2F608F655D9FAD86E2A85FD2B3FD9330E0BD5FE655ED3A"
    "685D5DC32C9D438CF519706ECC42AFA309413871B257D5D46E70788268BC0A71C00ED3725E"
    "C20A6C9E67A52E9B51B223EE2EA3C3BB8F6F05E32F89339D419254BC0A65047797233BCB1D"
    "4A03D6CB1758EFC16602E648136775F1E6F62CED69F83CDD9888AEF55334C1AEBB3FBED761"
    "88320FDB0EFBFC2591BB619080E3F826738D22195733EE21DD4925FB7268F2EE7F6948D7AD"
    "B0949FDDDBF78D47C21C6E6C7D3D87BF0238DDEB099E8B84F36F1325526CCECB399F3122E8"
    "C51ACC51CABB3A64FA8E1089394CED61DD5A0C9CE216D7AD4F54066529D6469FA308D522C2"
    "036822BB9E228B8AA2CC4681BF2C517F736D8D84700FB50D73F15658745DE2D4CC27AA44DF"
    "07BA57B61D42681E4C51A92ACA9E9E44882A925AA6C5D3C8793668009384CD230727F49D6B"
    "84C00698BCC8BEF58694430B07F91E429E754C4128E53BB5C62A2F9";

T_MACHINE(CHAOS_MACHINE_NCG, ncg__cerf__0, ncg__cerf__1)

/// xorring ////////////////////////////////////////////////////////////////////

std::string xorring32__cerf__0 =
    "80A6FDC85540024088964C26AC91991A4E8249A8C67AE8A0BA20C2402BAE2D8058B49FFED2"
    "3B904CEA2FA8295BA7DC488D9E4329AF700194B4EFF1C34806D587810E55C8AA6B90B0CF2B"
    "8BCCE55E8B585555F80FDA375D20121B4E7452DE0F4B3CDA9FE6B9593182C8C8296536DEDA"
    "2F493B248F4DE1E846F42431DC749C742C491EBB41956EEA09507C9DA108A332E801AFC7E9"
    "3E497ECC20FA87918003174736F938483C8399C34B9326CC4A82384B58C027CDC5EA8FF598"
    "EB228D8B80AF819FE082073E4039AF18049FCD7C3AD61C273548845D9B39CB8B05B004CE37"
    "7B337D0A8291B8F513814094DF01A3B39F4FA4B6F98C941B42841193241FEC59504BAD5483"
    "0F61CA2186EC49014D898652482C3283322811E2155460881B1A52B61C3B13B5A812FA58BD"
    "893730D598BC22A6ED5A51A8BE6DAA786685D4D6A4AD822141B379B4E4F7560ADDC44BFC2C"
    "DB6BB1EC38C2BBADC4DA9C77E14C04A3DC279B12130A78D57646AA6F0F49A01A168A20FF83"
    "4438C5ED1787016099EFE29A5115E0906CDC161BF79C7BF65693F3EF8BAC49A559DF8F71E9"
    "91E812E49179EDD4F949FE0DBC8CEEF0D1CCF644D5EE820A290CD28F6FDA4366F278BF864A"
    "3B1BC44D85635765E8566F96F919D15C45B94EE8494A987F5A083A8C19440B2B277C15DAA9"
    "C46E423E9D5C83DFF2CD09D353820DC86FB161DAB421FA3BC7849B6";

std::string xorring32__cerf__1 =
    "4F9BBE9DF3142E0CC80D989718D6785A1AE450D762F0CE3C852A1CD8C9F0B8AFEEB6C8DE5C"
    "405D920A711A71056D386EAA0D28383BF65E69DF9CD5E5607424EF00104F3537E09C97A628"
    "C28072EAC0FA07B77AFBD964CF623A48E9AA88209A813750B09E8618E23570ACC76D55FAB2"
    "E4D2CDBC787C79CCAA74ED622DA74C9BD7AEC2D0B009723DFBA1F2C0C199C0863A11FB83F3"
    "F3689EEC22C417C5CE9EB5ECC207B9B38245A62FA36E5C0BD6DBC19C8E104125FA5C342C70"
    "D932E0FAA0918535835CFC842ABFDC91F62438603BA0B01BB01286CAADACD45DF4AF126FBF"
    "5CC87CAE02987D674E4FB4AE5018A3E73AA223A63663A37B68A6D8EECDE47FB2941857F970"
    "F492C66B48DB7FC1F83E6A9F8CFA9C95F4656255CF52288C4CDC6214504E2523AE3B44EDE2"
    "72BBE135D4326533755C26DA90B1D5CCCE0CE7296D013768646AAEA09EF14581473D226A06"
    "4638B3AFAA85E1CDF150F27786D60309941CE2D451062F7FB6D55B72116A826D6876B5275F"
    "76F3C2ACA6536FE848F9FDCE5A3505DF085E78D040D3B2413AD5D1B07D6C67E82CBE650944"
    "D74FE9B28A73107A8B1808B86B569BF6A06819A8AA94D1A0307A93A2B715D436ED1C3EFEB4"
    "8A19A0CEE69C57CFBF39643CE1E4304F7DDC2EF387F373C5DA05B7179DEC6A3BF5A6DA6AE3"
    "DAE6EBC226AD1F8C4D85A1851791EF70011F32CACD2A01219A7";

T_MACHINE(CHAOS_MACHINE_XORRING32, xorring32__cerf__0, xorring32__cerf__1)

std::string xorring64__cerf__0 =
    "3C3C15606A2EC6503B42F72C6CEB74A5B0AFE071A0A3129A7A93EE630E229FEC8D13EA5989"
    "C7CEDF2BAE83F5ECC06CB96C8A21BD0186446C4548B993E6077F539790F6D893807DC2BA8E"
    "3F058C1687A369408EB8D4A1DAF0A7501BC0D456E9DE87313838853483A814389218CE8CD6"
    "2F5B63D62EB2B13F524C80DEFBC948C27E15763DD0C6D828FE0CDE7C3E19E0F38BE9DE835A"
    "40AA2DED170A0885C20F12322BC22E47A2E14E801FD536360DC464A9BE6CBDF436448819D0"
    "82670BD6C8788568292484A327C9A914A6F5534FCABE3C883E086E0D284B152866B61B336A"
    "A729052D4F69AD26E11518E5C1AB30B47BA89344A664B226F0548C0839244095418FAB07DC"
    "048FDE99A92A037F3461834F3AF7BB3F5CD781B391FD8152246A8BF03F6D8A97ABE487B80E"
    "49477206015248100849C738DEF2F2E40B27F29F489E28AF0E2E07532A37BBD00366AE21CD"
    "9AAEF367B36ACA3282AAE802538789118233DB0BB58C59D213495CD1C90992074BE1956468"
    "67F0475C40A28792ECE30ACCD68DC65FB5396428BF058DF0C1E7BFB10367C37E005B14D245"
    "21328BC1F447007800F8291CDF544181224B5115CBCC3959F34B354C45EC22F99AEDA42871"
    "EF2D47CCA467D7EDC3AB8DCF1DAEFB6A26B76B9746229144EEE28CBC8A69624089EF99FF47"
    "2CEC9951A871B42D767B10AA639E54E458CBBE6C06FDDF529A05088";

std::string xorring64__cerf__1 =
    "BC19F68F88D287C94B3C353AE3892C45C168AE7272CC38C334DDF8519372AA060B486303A5"
    "8EBB2414D75B884BF8AC881AE8672D1AB259A4270C516DCEC1C4047A88919438FD0FF637EF"
    "FDEAA6E520463D3CAEFF25CE3E05E32145D9B362F25A5DE2420303772547F0936CCD62479C"
    "437CFDA4FE70CA4A08A876FB43181F814375AE7F4E900EE234EFC87142C4AB46A1ECF0C7D7"
    "A81A048B68883B7E94FCF39B349803031324A304E32898C36556C4C9E4E7AE94643E90B936"
    "54357EBEAA3A2F9D5E4048D9DD78B78C36293CABFCA0D6DBC16F614C0EF85FE7A294A8A766"
    "D82B9A075DE7BB790D69A1104B4E1BA09A562CEBC928227FC4EEE9B60BBB469DED17433DC4"
    "1EE2799D2A8760B8CDB9F8A4DB30C8F2AD2F9CF462F94242505A110AAE086EF1704367E37E"
    "D6DABE430680C8D82499438C478433ABD88EBEEB750E7C68F7A7959EB5CF11F88263F2E1A4"
    "85DA40A3488BCF25891D41B38DD0D03E0B707718DC0AD476461FC7EA3A457BE4FEB1A66CAF"
    "614D371B34B2408AEB9B7A2B96FDA84BFF552C173FA34CF2BFBC14A9B48714F8B34BF48FD8"
    "C2F3318F5B00F9F9F40D5729BB2F2EBFE7258CCB64B9C5ECB4A43CFDC0D76B302E0119650A"
    "F052988497F36F073399FE4D6A787063462887BD67263985D433F5F4C36C653B4FB3E89982"
    "A6B01D0267E3C372B6BE23D73DC5B61261D8188B7E08C0581A220A";

T_MACHINE(CHAOS_MACHINE_XORRING64, xorring64__cerf__0, xorring64__cerf__1)
